include ./makefile.inc
ISA=imac
# ------------------------------------- Makefile TARGETS ----------------------------------------- #

default: generate_verilog

MOREDEFINES=$(addprefix -D , $(BSC_DEFINES))
Vivado_loc=$(shell which vivado || which vivado_lab)

%.bo:
	$(info building $@)
	@$(BSCCMD) $(MOREDEFINES) -p $(BSVINCDIR) $<

# -------------------------------------- Hardware generation Targets ----------------------------- #
.PHONY: generate_verilog
generate_verilog: $(BSVBUILDDIR)/$(TOP_BIN)
	@cp ${BS_VERILOG_LIB}/../Verilog.Vivado/RegFile.v ${VERILOGDIR}
	@cp ${BS_VERILOG_LIB}/FIFO2.v ${VERILOGDIR}
	@cp ${BS_VERILOG_LIB}/FIFO1.v ${VERILOGDIR}
	@cp ${BS_VERILOG_LIB}/FIFO10.v ${VERILOGDIR}
	@cp ${BS_VERILOG_LIB}/FIFOL1.v ${VERILOGDIR}
	@cp ${BS_VERILOG_LIB}/Counter.v ${VERILOGDIR}
	@cp ${BS_VERILOG_LIB}/SizedFIFO.v ${VERILOGDIR}
	@cp ${BS_VERILOG_LIB}/ResetEither.v ${VERILOGDIR}
	@cp ${BS_VERILOG_LIB}/MakeReset0.v ${VERILOGDIR}
	@cp ${BS_VERILOG_LIB}/SyncReset0.v ${VERILOGDIR}
	@cp ${BS_VERILOG_LIB}/SyncBit.v ${VERILOGDIR}
	@cp ${BS_VERILOG_LIB}/SyncPulse.v ${VERILOGDIR}
	@cp ${BS_VERILOG_LIB}/ClockInverter.v ${VERILOGDIR}
	@cp ${BS_VERILOG_LIB}/SyncFIFO1.v ${VERILOGDIR}
	@cp ${BS_VERILOG_LIB}/SyncFIFO.v ${VERILOGDIR}
	@cp ${BS_VERILOG_LIB}/SyncRegister.v ${VERILOGDIR}
	@cp ${BS_VERILOG_LIB}/SyncHandshake.v ${VERILOGDIR}
	@cp ${BS_VERILOG_LIB}/RevertReg.v ${VERILOGDIR}
	@cp ${BS_VERILOG_LIB}/UngatedClockMux.v ${VERILOGDIR}
	@cp ${BS_VERILOG_LIB}/MakeClock.v ${VERILOGDIR}
	@cp ${BS_VERILOG_LIB}/../Verilog.Vivado/BRAM1Load.v ${VERILOGDIR}
	@cp ${BS_VERILOG_LIB}/TriState.v ${VERILOGDIR}
	@cp bsvwrappers/common_lib/*.v ${VERILOGDIR}
	@cp devices/plic/*.v ${VERILOGDIR}

.PHONY: generate_hexfiles
generate_hexfiles:
	@mkdir -p $(BSVOUTDIR)
	@cd software; make boot
	@cp software/build/boot.mem ${VERILOGDIR}/
	@cp software/build/boot.mem ${BSVOUTDIR}/
	@cd software; make PROGRAM=hello ocmhex
	@cp software/build/ocm.mem ${VERILOGDIR}/
	@cp software/build/ocm.mem ${BSVOUTDIR}/
	@cd software; make PROGRAM=hello ddrhex
	@cp software/build/ddr.mem ${VERILOGDIR}/
	@cp software/build/ddr.mem ${BSVOUTDIR}/

.PHONY: link_verilator
link_verilator: ## Generate simulation executable using Verilator and VPI for GDB
	@echo "Linking Verilator With the remotebitbang Vpi"
	@mkdir -p $(BSVOUTDIR) obj_dir
	@echo "#define TOPMODULE V$(TOP_MODULE)_edited" >sim_main.h
	@echo '#include "V$(TOP_MODULE)_edited.h"' >> sim_main.h
	@sed  -f devices/jtagdtm/sed_script.txt  $(VERILOGDIR)/$(TOP_MODULE).v > tmp1.v
	@cat  devices/jtagdtm/verilator_config.vlt \
	      devices/jtagdtm/vpi_sv.v \
	      tmp1.v                         > $(VERILOGDIR)/$(TOP_MODULE)_edited.v
	@rm   -f  tmp1.v
	verilator $(VERILATOR_FLAGS) --threads-dpi all --cc $(TOP_MODULE)_edited.v --exe sim_main.cpp devices/jtagdtm/remotebitbang.c -y $(VERILOGDIR)
	@ln -f -s ../sim/sim_main.cpp obj_dir/sim_main.cpp
	@ln -f -s ../sim_main.h obj_dir/sim_main.h
	@ln -f -s ./devices/jtagdtm/remotebitbang.c obj_dir/remotebitbang.c
	@echo "INFO: Linking verilated files"
	make $(VERILATOR_SPEED) VM_PARALLEL_BUILDS=1 -j4 -C obj_dir -f V$(TOP_MODULE)_edited.mk
	@cp obj_dir/V$(TOP_MODULE)_edited $(BSVOUTDIR)/chromitem_soc
	@echo Linking finished

.PHONY: ip_build
ip_build: ## build Xilinx Core-IPs used in this project
	@echo "Creating IPs for $(FPGA_BOARD_ALIAS) $(FPGA_BOARD) $(FPGA_PART) $(ISA) $(JOBS)"
	@vivado -log ipbuild.log -nojournal -mode tcl -notrace -source common_tcl/create_ip_project.tcl \
		-tclargs $(FPGA_BOARD_ALIAS) $(FPGA_BOARD) $(FPGA_PART) $(ISA) $(JOBS) \
		|| (echo "Could not create IP project"; exit 1)

.PHONY: fpga_build
fpga_build:
	vivado -nojournal -nolog -mode tcl -notrace -source common_tcl/create_project.tcl -tclargs $(FPGA_BOARD_ALIAS) $(FPGA_BOARD) $(FPGA_PART) $(JTAG_TYPE) $(VERILOGDIR)\
	|| (echo "Could not create core project"; exit 1)
	vivado -nojournal -log fpgabuild.log -notrace -mode tcl -source common_tcl/run.tcl \
		-tclargs $(JOBS) || (echo "ERROR: While running synthesis")

.PHONY: generate_mcs
generate_mcs:
	vivado -nojournal -nolog -mode tcl -source common_tcl/generate_mcs.tcl

.PHONY: program_mcs
program_mcs: ## Program the FPGA Configuration Memory in order to use the onboard ftdi jtag chain
	vivado -nojournal -nolog -mode tcl -source fpga/$(FPGA_BOARD_ALIAS)/program_mcs.tcl
	@echo "Please Disconnect and reconnect Your FPGA Board from your PC"

.PHONY: clean_hw
clean_hw:
ifneq ($(BSVBUILDDIR),"")
	@rm -rf $(BSVBUILDDIR)/*
endif
ifneq ($(BSVOUTDIR),"")
	@rm -rf $(BSVOUTDIR)/*
endif
ifneq ($(VERILOGDIR),"")
	@rm -rf $(VERILOGDIR)/*
endif
ifneq ($(FPGA_BUILD_DIR),"")
	@rm -rf $(FPGA_BUILD_DIR)/*
endif
	rm -f *.jou rm *.log *.mem log sim_main.h cds.lib hdl.var
# ------------------------------------------------------------------------------------------------ #

export RISCV_PREFIX=riscv$(XLEN)-unknown-elf-
export RISCV_GCC=$(RISCV_PREFIX)gcc
export RISCV_OBJDUMP=$(RISCV_PREFIX)objdump
export RISCV_GCC_OPTS=-mcmodel=medany -static -std=gnu99 -O2 -ffast-math \
-fno-common -fno-builtin-printf -fno-tree-loop-distribute-patterns -DCUSTOM \
-DFL_BOOTADDR=$(FLASH_BASE_ADDR)
export RISCV_LINK_OPTS=-w -static -nostdlib -nostartfiles -lm -lgcc
export PROGRAMS_DIR=software/programs/
export RISCV_INC= -I$(PWD)/software/common/
export RISCV_MARCH=rv$(XLEN)$(ISA)
export SW_BUILD=$(PWD)/build/sw
export RISCV_LINK=$(PWD)/software/common/link.ld

$(SW_BUILD)/crt.o:
	@ mkdir -p $(SW_BUILD)/
	@$(RISCV_GCC) -g $(RISCV_GCC_OPTS) $(RISCV_LINK_OPTS) $(RISCV_INC) -march=$(RISCV_MARCH) \
		 -c software/common/crt.S -o $(SW_BUILD)/crt.o
$(SW_BUILD)/syscalls.o:
	@ mkdir -p $(SW_BUILD)/
	@$(RISCV_GCC) -g $(RISCV_GCC_OPTS) $(RISCV_LINK_OPTS) $(RISCV_INC) -march=$(RISCV_MARCH) \
		 -c software/common/syscalls.c -o $(SW_BUILD)/syscalls.o

PROGRAM?=hello

.PHONY: list-programs
list-programs:
	@ echo program-list: $(shell ls $(PROGRAMS_DIR)/)

.PHONY: connect_gdb
connect_gdb: $(SW_BUILD)/crt.o $(SW_BUILD)/syscalls.o
ifneq ("$(wildcard $(ELF))","")
	@ echo "Loading $(ELF)"
	@ ./software/debug_script.sh --elf $(ELF) --openocd-config fpga/$(FPGA_BOARD_ALIAS)/ocd.cfg
else
	@ echo "Compiling $(PROGRAM)"
	@ cd $(PROGRAMS_DIR)/$(PROGRAM); $(MAKE)
	@ echo "Loading $(SW_BUILD)/$(PROGRAM)"
	@ ./software/debug_script.sh --elf $(SW_BUILD)/$(PROGRAM) --openocd-config fpga/$(FPGA_BOARD_ALIAS)/ocd.cfg
endif

#---------------------------------------------------------------------------------------------------
.PHONY: flash
flash:
ifneq ("$(wildcard $(ELF))","")
	@mkdir -p $(SW_BUILD)/
	@rm -rf $(SW_BUILD)/*.bin
	@make prep_binary --no-print-directory
else
	@echo "Provide absolute path of ELF with flash command"
endif

prep_binary: create_binary eval_binary endian_shift eval_final_bin exec_openocd binary_clean

create_binary:
	@$(RISCV_PREFIX)objcopy -O binary $(ELF) $(SW_BUILD)/elf_le.bin
eval_binary:
	@$(eval FILE_SIZE:=$(shell stat -c%s $(SW_BUILD)/elf_le.bin) )
endian_shift:
	@hexdump -v -e '1/4 "%08x"' -e '"\n"' $(SW_BUILD)/elf_le.bin | xxd -r -p > $(SW_BUILD)/elf.bin
	@printf "%08x\n" $(FILE_SIZE) > $(SW_BUILD)/size.txt
	@xxd -r -p $(SW_BUILD)/size.txt $(SW_BUILD)/output.bin
	@cat $(SW_BUILD)/elf.bin >> $(SW_BUILD)/output.bin
eval_final_bin:
	@$(eval FILE_SIZE:=$(shell stat -c%s $(SW_BUILD)/output.bin) )
	@$(eval AV_SPACE :=$(shell echo $(FLASH_MAX_ADDR)-$(FLASH_BASE_ADDR) | bc ))
exec_openocd:
	@if [ $(FILE_SIZE) -gt $(AV_SPACE) ]; then \
		echo $(FILE_SIZE) "is exceeding Flash's " $(AV_SPACE) " Capacity !"; \
		exit 1; \
	fi
	openocd -f fpga/$(FPGA_BOARD_ALIAS)/ocd.cfg -c "program \
		$(SW_BUILD)/output.bin preverify verify reset exit $(FLASH_BASE_ADDR)"
binary_clean:
	@rm -rf $(SW_BUILD)/*.txt $(SW_BUILD)/*.bin
#---------------------------------------------------------------------------------------------------

.PHONY clean_sw:
clean_sw:
ifneq ($(SW_BUILD),"")
	@rm -rf $(SW_BUILD)/*
endif

